/**
 * 
 */
package org.epanetgrid.otimizacao.tui;

import java.util.LinkedList;
import java.util.List;

import org.epanetgrid.otimizacao.OtimizadorEvent;
import org.epanetgrid.otimizacao.OtimizadorObserver;
import org.epanetgrid.otimizacao.ag.ViaveisSelector;
import org.epanetgrid.otimizacao.log.AGLogger;
import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.DefaultPopulation;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.Population;
import org.joda.time.DateTime;


/**
 * @author alan
 *
 */
public class StatusOtimizacao implements OtimizadorObserver {

	private int geracao;
	private boolean stopped;
//	private FitnessToDoubleTransformation[] transformations;
	private Population currentPopulation;
	private int objetivos;

	
	/**
	 * @param otimizador
	 */
	public StatusOtimizacao(int objetivos) {
		this.objetivos = objetivos;
		this.geracao = 0;
		this.stopped = false;
		
//		transformations = new FitnessToDoubleTransformation[indices.length];
//		for (int i = 0; i < indices.length; i++) {
//			transformations[i] = new DoubleFitnessToDoubleTransformation();
//		}
	}
	
	public synchronized void update(OtimizadorEvent event) {
		
		switch (event.getType()) {
		
		case OtimizadorEvent.INICIO:
			String msg = "Otimização iniciada";
			System.out.println(msg + " em " + new DateTime().toString("dd/MM/yyyy HH:mm:ss"));
			AGLogger.getInstance().info(msg);
			break;
		case OtimizadorEvent.PAUSE:
			msg = "Otimização pausada";
			System.out.println(msg);
			AGLogger.getInstance().info(msg);
			break;
		case OtimizadorEvent.FINAL:
		case OtimizadorEvent.TEMPO_LIMITE:
			this.stopped = true;
			msg = "Otimização finalizada";
			System.out.println(msg);
			AGLogger.getInstance().info(msg);
			break;
		case OtimizadorEvent.NAO_CONVERGENCIA:
			msg = "Todos os indivíduos da população não convergiram hidraulicamente. A otimização foi interrompida.";
			System.out.println(msg);
			AGLogger.getInstance().info(msg);
			break;
		case OtimizadorEvent.ERRO:
			if ( !stopped ) {
				msg = "Não foi possível otimizar.";
				System.out.println(msg);
				AGLogger.getInstance().info(msg);
			}
			break;
			
		case OtimizadorEvent.PASSO:

			if ( stopped ) {
				return;
			}
			
			final GAStatus status = (GAStatus) event.getData();
			
			currentPopulation = status.getCurrentPopulation();
			
			geracao++;
			
			msg = "****** GERAÇÂO " + geracao + " ******";
			System.out.println(msg);
			AGLogger.getInstance().info(msg);

			/*
			 * TODO: LOGAR POPULAÇAO
			 */
			
			
			if (objetivos > 1) {
				List<Comparable> minimos = new LinkedList<Comparable>();
				
				Individual[] individuos = status.getCurrentPopulation().toIndividualArray();
				
				for (int i = 0 ; i < objetivos; i++) {
					int index = 0;
					
					Comparable min = (Comparable)((List) individuos[0].getDataApplication()).get(i);
					
					for (int j = 1; j < individuos.length; j++) {
						Comparable value = (Comparable)((List) individuos[j].getDataApplication()).get(i);
					
						if (min.compareTo(value) > 0) {
							index = j;
							min = value;
						}
					}
					minimos.add(individuos[index]);
				}

				StringBuffer buffer = new StringBuffer("Mínimos globais:\n");
				System.out.println("\tMínimos globais:");
				for (Comparable minimo : minimos) {
					Individual individual = (Individual) minimo;
					System.out.println("\t" + individual.getDataApplication());
					buffer.append(OtimizacaoUtil.format(individual));
				}
				AGLogger.getInstance().info(buffer);
				
				//recuperando os minimos viaveis
				List<Comparable> minimosViaveis = new LinkedList<Comparable>();
				
				Population viaveis =  new DefaultPopulation();
				viaveis.addIndividuals(new ViaveisSelector().select(status.getCurrentPopulation(), 0, null, null));
				
				Individual[] bestObjectivesViaveis = viaveis.toIndividualArray();
				
				if(bestObjectivesViaveis.length != 0){
					for (int i = 0 ; i < objetivos; i++) {
						int index = 0;
						Comparable min = (Comparable) ( ((List) bestObjectivesViaveis[index].getDataApplication()).get(i));
						for (int j = 1; j < bestObjectivesViaveis.length; j++) {
							Comparable value = (Comparable) ( ((List) bestObjectivesViaveis[j].getDataApplication()).get(i));
							if (min.compareTo(value) > 0) {
								index = j;
								min = value;
							}
						}
						minimosViaveis.add(bestObjectivesViaveis[index]);
					}
					
				}
				if (!minimosViaveis.isEmpty()) {
					buffer = new StringBuffer("Mínimos viáveis:\n");
					System.out.println("\tMínimos viáveis:");
					for (Comparable minimo : minimosViaveis) {
						Individual individual = (Individual) minimo;
						System.out.println("\t" + individual.getDataApplication());
						buffer.append(OtimizacaoUtil.format(individual));
					}
					AGLogger.getInstance().info(buffer);					
				}
				
			} else {

				Individual individual = status.getCurrentPopulation().getIndividual(0);

				System.out.println("\tMínimo:");
				System.out.println("\t" + individual.getDataApplication());
				StringBuffer buffer = new StringBuffer("Mínimo:\n");
				buffer.append(OtimizacaoUtil.format(individual));
				AGLogger.getInstance().info(buffer);
			}

			break;
		}
	}

}
